package com.ccp.dev.system.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.consts.SystemConst;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.basic.web.query.QueryFilter;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringPool;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.system.dao.SysRoleDao;
import com.ccp.dev.system.model.*;
import com.ccp.dev.system.util.CookieUitl;
import com.ccp.dev.system.util.SubSystemUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 对象功能:系统角色表 Service类
 * @author : y
 */
@Service
public class SysRoleService extends BaseService<SysRole> {

	@Resource
	private SysRoleDao sysRoleDao;
	@Resource
	private SubSystemService subSystemService;
	@Resource
	private RoleResourcesService roleResourcesService;
	@Resource
	private ResourcesService resourcesService;
	@Resource
	private UserRoleService userRoleService;
	@Resource
	private SysTenantDynamicDataService sysTenantDynamicDataService;
	@Resource
	private SysOrgService sysOrgService;
	@Resource
	private SysTenantOrgService sysTenantOrgService;


	/**
	 * 保存或更新角色信息
	 * @param sysRole 参数
	 */
	@Transactional(rollbackFor = Exception.class)
	public void saveRole(SysRole sysRole) throws Exception{
		String orgId = sysRole.getOrgId();
		String systemId = sysRole.getSystemId();
		String curUserId = ContextUtil.getCurrentUserId();
		SubSystem subSystem = subSystemService.getOneById(systemId);
		String roleAlias=subSystem.getAlias() + StringPool.UNDERSCORE +sysRole.getAlias();
		sysRole.setAlias(roleAlias);

		Map<String,Object> params = new HashMap<>();
        if(StringUtil.isNotEmpty(sysRole.getRoleId())){
            String roleId = sysRole.getRoleId();
            SysRole oldRole = this.sysRoleDao.getById(roleId);

			if(SystemConst.DEFAULT_ROLE_CATEGORY.equals(sysRole.getCategory())){
				params.put("tenantId",sysRole.getTenantId());
				params.put("category", SystemConst.DEFAULT_ROLE_CATEGORY);
				params.put("roleId", sysRole.getRoleId());
				SysRole defaultRole = this.sysRoleDao.queryIsDefaultRole(params);
				if(BeanUtils.isNotEmpty(defaultRole)){
					throw new Exception("sysRole.addEditRole.isExist");
				}
			}

            //不允许编辑
            if(!isContainThreeRole(curUserId) && SysRole.ALLOWEDIT_N.equals(oldRole.getAllowEdit())){
                throw new Exception("sysRole.editRole.noEditWarning");
            }
            //三员角色
            if(SysRole.DEFAULT_THREEROLE.equals(oldRole.getIsPublic())) {
                throw new Exception("sysRole.editRole.threeRoleWarning");
            }
            //别名控制
            boolean isExist = isExistRoleAlias(roleAlias,sysRole.getRoleId());
            if(isExist){
                throw new Exception("sysRole.editRole.aliasWarning");
            }
			publicRoleWarning(roleId);
            sysRole.setUpdateBy(curUserId);
            sysRole.setUpdateTime(new Date());
            this.sysRoleDao.update(sysRole);
        }else{
			String tenantId;
        	if(StringUtil.isNotEmpty(orgId)){
				SysOrg sysOrg = sysOrgService.getSysOrgById(orgId);
				if(sysOrg.getIsTenant() == 0){
					//不是租户直接throw  组织不能增加角色
					throw new Exception("sysRole.editRole.orgWarning");
				}
				tenantId = sysTenantOrgService.getTenantIdByOrgId(orgId);
			}else{
				SysOrg sysOrg = sysOrgService.getSysOrgById(ContextUtil.getCurrentOrgId());
				if(sysOrg.getIsTenant() == 0){
					//不是租户直接throw  组织不能增加角色
					throw new Exception("sysRole.editRole.orgWarning");
				}
				tenantId = ContextUtil.getCurrentUserTenantId();
			}
			if(SystemConst.DEFAULT_ROLE_CATEGORY.equals(sysRole.getCategory())){
				params.put("tenantId",tenantId);
				params.put("category", SystemConst.DEFAULT_ROLE_CATEGORY);
				params.put("roleId",sysRole.getRoleId());
				SysRole defaultRole = this.sysRoleDao.queryIsDefaultRole(params);
				if(BeanUtils.isNotEmpty(defaultRole)){
					throw new Exception("sysRole.addEditRole.isExist");
				}
			}
            //新增判断别名是否存在
            boolean isExist = isExistRoleAlias(roleAlias,null);
            if(isExist){
                throw new Exception("sysRole.editRole.aliasWarning");
            }
            String newRoleId = UUIDUtils.getUUIDFor32();
			sysRole.setTenantId(tenantId);
            sysRole.setRoleId(newRoleId);
            sysRole.setCreateBy(curUserId);
            sysRole.setCreateTime(new Date());
            this.sysRoleDao.add(sysRole);
            //如果是默认子系统的角色给予分配所有公共资源
            if(SubSystem.DEFAULT_SYSTEM_ID.equals(systemId)) {
                //将所有公共资源添加到角色和资源映射表SYS_ROLE_RES
                addRoleRes(tenantId,systemId,sysRole);
            }
            //增加租户角色映射
            sysTenantDynamicDataService.addSysTenantDynamicData(newRoleId,tenantId,SysRole.class);
        }
	}

	@Transactional
	public void addRoleRes(String tenantId,String systemId,SysRole sysRole){
		Map<Object,Object> map = new HashMap<>(2);
		map.put("isPublic", Resources.IS_PUBLIC_Y);
		map.put("tenantId",tenantId);
		List<Resources> resourcesList = resourcesService.queryAllPublicRes(map);
		for (Resources res : resourcesList) {
			RoleResources roleResources = new RoleResources();
			roleResources.setRoleResId(UUIDUtils.getUUIDFor32());
			roleResources.setResId(res.getResId());
			roleResources.setSystemId(systemId);
			roleResources.setRoleId(sysRole.getRoleId());
			//为了数据库适配 ， 所有循环用add 而不用 addList
			this.roleResourcesService.add(roleResources);
		}
	}

	/**
	 * 根据租户id查询是否有默认角色
	 * @param tenantId 参数为租户id
	 * @return 返回查询到的角色信息
	 */
	public SysRole queryIsDefaultRole(String tenantId){
		Map<String,Object> params = new HashMap<>();
		params.put("tenantId",tenantId);
		params.put("category", SystemConst.DEFAULT_ROLE_CATEGORY);
		SysRole defaultRole = this.sysRoleDao.queryIsDefaultRole(params);
		return defaultRole;
	}

	/**
	 * 是否存在角色别名
	 * @param roleAlias 角色别名
	 * @param roleId  角色id
	 * @return true 存在 false 不存在
	 */
	public boolean isExistRoleAlias(String roleAlias,String roleId){
		Map<Object,String> map = new HashMap<>(2);
		int count;
		if(StringUtil.isEmpty(roleId)){
			map.put("roleAlias",roleAlias);
			count = this.sysRoleDao.isExistRoleAlias(map);
		}else{
			map.put("roleAlias",roleAlias);
			map.put("roleId",roleId);
			count = this.sysRoleDao.isExistRoleAlias(map);
		}
		return count > 0;
	}

	/**
	 * 添加默认角色信息并分配公共资源
	 * @param sysOrg 组织信息
	 * @param tenantId 租户id
	 * @param systemId 子系统id
	 * @param publicResList 公共资源
	 */
	public void addDefaultRole(SysOrg sysOrg,String tenantId,String systemId,List<Resources> publicResList){
		//添加默认角色信息
		SysRole sysRole = new SysRole();
		String roleId = UUIDUtils.getUUIDFor32();
		sysRole.setRoleId(roleId);
		sysRole.setRoleName(sysOrg.getOrgName()+SystemConst.DEFAULT_ROLE_CATEGORY);
		SubSystem subSystem = subSystemService.getOneById(systemId);
		sysRole.setAlias(subSystem.getAlias() + StringPool.UNDERSCORE+sysOrg.getCode()+"mrjs");
		sysRole.setAllowDel(SystemConst.ROLE_ALLOW_DEL);
		sysRole.setAllowEdit(SystemConst.ROLE_ALLOW_EDIT);
		sysRole.setEnabled(SystemConst.ROLE_ENABLED);
		sysRole.setCategory(SystemConst.DEFAULT_ROLE_CATEGORY);
		sysRole.setEnableSwitch(SystemConst.ROLE_ENABLEDSWITCH);
		sysRole.setIsPublic(SystemConst.ROLE_ISPUBLIC);
		sysRole.setTenantId(tenantId);
		sysRole.setCreateBy(ContextUtil.getCurrentUserId());
		sysRole.setCreateTime(new Date());
		sysRole.setSystemId(systemId);
		this.add(sysRole);
		//默认角色添加公共资源信息
		addRoleRes(tenantId,systemId,sysRole);
		//增加租户与角色映射
		sysTenantDynamicDataService.addSysTenantDynamicData(roleId,tenantId,SysRole.class);
	}

    /**
     * 根据角色id删除model以及关联
	 * @param ids 角色id
     * @return int
	 */
	@Transactional(rollbackFor = Exception.class)
	public void delRoleByIds(String[] ids) throws Exception{
        if(null == ids){
            throw new Exception("delete.failure");
        }
        String curUserId = ContextUtil.getCurrentUserId();
        int state = 0;
		boolean isContainOwn;
		for(String id : ids){
			//当前用户所拥有启用的角色
		    List<SysRole> sysRoleList = this.sysRoleDao.queryByUserId(curUserId);
            isContainOwn = false;
		    for(SysRole sysRole : sysRoleList){
                if(id.equals(sysRole.getRoleId())){
                    isContainOwn = true;
                    break;
                }
            }
		    SysRole sysRole = this.sysRoleDao.getById(id);
		    if(SysRole.ALLOWDEL_N.equals(sysRole.getAllowDel())){
                state = 1;
				//不允许删除不能删除
				continue;
			}
		    if(isContainOwn){
                state = 2;
                //自己包含的角色不能删除
                continue;
            }
		    if(SysRole.DEFAULT_THREEROLE.equals(sysRole.getIsPublic())){
                state = 3;
		        //三员角色不能删除
		        continue;
            }
			if(SysRole.DEFAULT_PUBLICROLE.equals(sysRole.getIsPublic())){
				//是公共角色
				String currTenantId = ContextUtil.getCurrentUserTenantId();
				String tenantId = sysTenantDynamicDataService.getTenantIdByDataId(id);
				if(!currTenantId.equals(tenantId)){
					//不是自己租户下的公共角色不能删除
					state = 4;
					continue;
				}
			}
			this.delById(id);
			this.userRoleService.delByRoleId(id);
			this.sysTenantDynamicDataService.delByDataId(id);
		}
        if(ids.length == 1){
            if(state == 1){
                throw new Exception("sysRole.delRole.noDelWarning");
            }
            if(state == 2){
                throw new Exception("sysRole.delRole.containWarning");
            }
            if(state == 3){
                throw new Exception("sysRole.delRole.threeRoleWarning");
            }
            if(state == 4){
				throw new Exception("sysRole.editRole.publicRoleWarning");
            }
        }else{
            if(state != 0){
                throw new Exception("sysRole.delRole.warning");
            }
        }
	}

    /**
     * 启用或者禁用角色
     * @param roleId 角色id
     */
	public void runEnableRole(String roleId) throws Exception{
        SysRole sysRole = this.getOneById(roleId);
        if(SysRole.ALLOWEDIT_N.equals(sysRole.getAllowEdit())){
            throw new Exception("sysRole.editRole.noEditWarning");
        }
		publicRoleWarning(roleId);
        if (SysRole.ENABLED_Y.equals(sysRole.getEnabled())) {
            sysRole.setEnabled(SysRole.ENABLED_N);
        } else {
            sysRole.setEnabled(SysRole.ENABLED_Y);
        }
        this.update(sysRole);
    }

	/**
	 * 不是自己租户下的公共角色不能编辑
	 * @param roleId
	 * @throws Exception
	 */
    public void publicRoleWarning(String roleId) throws Exception{
		SysRole sysRole = this.getOneById(roleId);
		if(SysRole.DEFAULT_PUBLICROLE.equals(sysRole.getIsPublic())){
			//是公共角色
			String currTenantId = ContextUtil.getCurrentUserTenantId();
			String tenantId = sysTenantDynamicDataService.getTenantIdByDataId(roleId);
			if(!currTenantId.equals(tenantId)){
				throw new Exception("sysRole.editRole.publicRoleWarning");
			}
		}
	}

	/**
	 * 根据用户id获取其的角色
	 * @param userId 用户id
	 * @return list
	 */
	public List<SysRole> queryByUserId(String userId){
		return this.sysRoleDao.queryByUserId(userId);
	}

	/**
	 * 获取三员角色
	 * @param roleType 三员角色类型 可填null
	 * @return list
	 */
	public List<SysRole> queryThreeMemberRole(Short roleType){
		return this.sysRoleDao.queryThreeMemberRole(roleType);
	}

	/**
	 * 根据用户获取用户角色别名
	 * @param userId 用户id
	 * @return list
	 */
	public List<String> getRolesByUserId(String userId){
		//获取用户角色。
		List<SysRole> userRoleList= queryByUserId(userId);
		List<String> userRoles=new ArrayList<>();
		if(BeanUtils.isNotEmpty(userRoleList)){
			for(SysRole role:userRoleList){
				userRoles.add(role.getAlias());
			}
		}
		return userRoles;
	}

	/**
	 * 是否包含三员角色
	 * @param userId 用户id
	 * @return true 包含  false 不包含
	 */
	public boolean isContainThreeRole(String userId){
		List<SysRole> sysRoleList = this.queryByUserId(userId);
		for(SysRole sysRole : sysRoleList){
			if(SysRole.DEFAULT_THREEROLE.equals(sysRole.getIsPublic())){
				return true;
			}
		}
		return false;
	}

	/**
	 * 根据组织id获取组织下的角色分类
	 * @param orgId  组织id
	 * @return	list
	 */
	public List<String> queryDistinctCategory(String orgId){
		List<String> orgIdList;
		if(StringUtil.isEmpty(orgId)){
			orgId = ContextUtil.getCurrentOrgId();
		}
		SysOrg sysOrg = sysOrgService.getOneById(orgId);
		String orgPath = sysOrg.getPath();
		String[] orgArray;
		if(orgPath.contains(".")){
			orgArray = orgPath.split("\\.");
		}else{
			orgArray = new String[]{orgPath};
		}
		List<String> orgPathForList = Arrays.asList(orgArray);
		List<String> orgPathForNewList = new ArrayList<>(orgPathForList);
		if(orgPathForNewList.indexOf(orgId) != -1){
			orgPathForNewList.remove(orgId);
		}
		orgIdList =orgPathForNewList;
		return this.sysRoleDao.queryDistinctCategory(orgId,orgIdList,SystemConst.DEFAULT_ROLE_CATEGORY);
	}

	/**
	 * 根据用户id查询角色列表
	 * @param queryFilter 参数
	 * @return	list
	 */
	public List<SysRole> queryOrgRoleByUserId(QueryFilter queryFilter){
		Object o = queryFilter.get("userId");
		if(StringUtil.isEmpty(o)){
			return  null;
		}
		String userId = queryFilter.get("userId").toString();
		SysOrg sysOrg = this.sysOrgService.getOrgByUserId(userId);
		queryFilter.put("orgId",sysOrg.getOrgId());
		queryFilter.put("enabled",SysRole.ENABLED_Y);
		List<SysRole> list = list(queryFilter);
		List<SysRole> retListRole = new ArrayList<>();
		List<UserRole> userRoleList = userRoleService.queryByUserId(userId);
		if(!userRoleList.isEmpty()){
			boolean b ;
			for(SysRole sysRole : list){
				b = true;
				for(UserRole userRole : userRoleList){
					if(sysRole.getRoleId().equals(userRole.getRoleId())){
						b = false;
					}
				}
				if(b){
					retListRole.add(sysRole);
				}
			}
			return retListRole;
		}else{
			return list;
		}
	}

	/**
	 * list查询
	 * @param queryFilter 查询条件
	 * @return list
	 */
	public List<SysRole> list(QueryFilter queryFilter){
		/**
		 * orgId不为空，代表点击租户树，查询当前点击租户上级公共角色+当前租户下角色
		 * orgId为空，代表点击菜单，默认查询当前租户上级公共角色+当前租户下角色+当前租户子租户角色
		 */
		Object orgId = queryFilter.get("orgId");
		boolean isOrgIdNull = false;
		//为空代表没有点击组织树
		if(StringUtil.isEmpty(orgId)){
			//为了查询当前组织下的角色
			orgId =  ContextUtil.getCurrentOrgId();
			isOrgIdNull = true;
		}
		SysOrg sysOrg = this.sysOrgService.getOneById(orgId.toString());
		String path = sysOrg.getPath();
		if(StringUtil.isNotEmpty(path)){
			if(isOrgIdNull){
				queryFilter.put("path", path + StringPool.PERCENT);
			}
			path = path.substring(0,path.length()-1);
			String[] orgArray;
			if(path.contains(".")){
				orgArray = path.split("\\.");
			}else{
				orgArray = new String[]{path};
			}
			//为了查询当前组织上级的公共角色
			queryFilter.put("orgIdList",Arrays.asList(orgArray));
		}
		return sysRoleDao.queryRolesByOrgId(queryFilter);
	}

	/**
	 * 根据id查询model
	 * @param roleId 角色id
	 * @return sysRole
	 */
	public SysRole get(String roleId){
		SysRole sysRole = this.getOneById(roleId);
		String systemId = sysRole.getSystemId();
		// 如果系统id不为空，则将角色别名系统前缀替换掉。
		if (StringUtil.isNotEmpty(systemId)) {
			SubSystem subSystem = subSystemService.getOneById(systemId);
			String sysAlias = subSystem.getAlias();
			String roleAlias = sysRole.getAlias().replaceFirst(sysAlias + StringPool.UNDERSCORE, "");
			sysRole.setAlias(roleAlias);
		}
		return sysRole;
	}

	/**
	 * 根据完整角色别名查询角色信息
	 * @param roleAlias 完整角色别名
	 * @return
	 */
	public SysRole getRoleByAllRoleAlias(String roleAlias){
		return this.sysRoleDao.getRoleByRoleAlias(roleAlias);
	}

	/**
	 * 根据角色别名查询角色信息
	 * @param roleAlias 角色别名
	 * @param request 请求
	 * @return
	 */
	public SysRole getRoleByRoleAlias(String roleAlias,HttpServletRequest request){
		//获取当前登录子系统别名
		String systemAlias = SubSystemUtil.getCurrentSystemAlias(request);
		//拼接角色别名
		roleAlias = systemAlias + StringPool.UNDERSCORE + roleAlias;
		return this.sysRoleDao.getRoleByRoleAlias(roleAlias);
	}

    /**
     * 根据子系统列表获取资源的URL和角色映射对象。
     * <br>
     * <pre>
     * 	ResourcesUrlExt 的url字段和role 别名。
     * 		1.从SYS_RES 的 defaultUrl获取。
     * 		2.从SYS_RESURL 表中获取。
     * </pre>
     * @param subSystemList 子系统别名list
     * @param url 请求url
     * @return map
     */
    public Map<String, Object> queryUrlRightMapBySubSystemList(List<SubSystem> subSystemList,String url){
        Map<String, Object> map=new HashMap<>();
        Set<String> roleSet=new HashSet<>();
        List<String> aliasList = new ArrayList<>();
        for(SubSystem subSystem:subSystemList){
            aliasList.add(subSystem.getAlias());
        }
        List<ResourcesUrlExt> defaultUrlList=resourcesService.queryDefaultUrlAndRoleByUrlSystemAliasList(aliasList, url);
        if(!defaultUrlList.isEmpty()){
            map.put("isUrlExist", true);
        }
        else{
            map.put("isUrlExist", false);
        }
        for(ResourcesUrlExt urlExt:defaultUrlList){
            if(StringUtil.isEmpty(urlExt.getRole())) {continue;}
            roleSet.add(urlExt.getRole());
        }
        List<String> roleList=new ArrayList<String>();
        roleList.addAll(roleSet);
        map.put("roleList", roleList);
        return map;
    }

	/**
	 * 查询本级租户下的普通角色
	 * @param tenantId 租户id
	 * @param systemId 系统id
	 * @return list
	 */
    public List<SysRole> queryCommonRolesByTenantId(String tenantId,String systemId){
		Map<String, Object> map=new HashMap<>();
		map.put("tenantId",tenantId);
		map.put("systemId",systemId);
    	return sysRoleDao.queryCommonRolesByTenantId(map);
	}

	/**
	 * 根据系统id获取可切换的角色
	 * @param systemId
	 * @return
	 */
	public List<SysRole> querySwitchBySystemId(String systemId){
		String userId = ContextUtil.getCurrentUserId();
		Map<String, Object> map=new HashMap<>();
		map.put("userId",userId);
		map.put("systemId",systemId);

		return sysRoleDao.querySwitchRoleBySystemId(map);
	}

	/**
	 * 写出role cookie
	 * @param roleId 角色id
	 * @param request HttpServletRequest
	 * @param response HttpServletResponse
	 */
	public void setCurrentRole(String roleId, HttpServletRequest request, HttpServletResponse response){
		SysRole sysRole=sysRoleDao.getById(roleId);
		if(sysRole!=null){
			writeCurrentRoleCookie(String.valueOf(roleId),  request,  response);
			request.getSession().setAttribute(SysRole.CURRENT_SYSROLE,sysRole);
		}
	}

	public void writeCurrentRoleCookie(String roleId, HttpServletRequest request, HttpServletResponse response){
		if (CookieUitl.isExistByName(SysRole.CURRENT_SYSROLE, request)) {
			CookieUitl.delCookie(SysRole.CURRENT_SYSROLE, request, response);
		}
		// 14 days
		int tokenValiditySeconds = 86400 * 14;
		CookieUitl.addCookie(SysRole.CURRENT_SYSROLE, roleId, tokenValiditySeconds, request, response);
	}

	/**
	 * 根据角色id查询角色名
	 * @param ids id数组
	 * @return list
	 */
	public List<String> queryRoleNameByRoleIds(String[] ids){
		if(BeanUtils.isEmpty(ids)){
			return null;
		}
		return this.sysRoleDao.queryRoleNameByRoleIds(Arrays.asList(ids));
	}

	/**
	 * 根据角色名称查询角色
	 * @param name
	 * @return
	 */
    public List<SysRole> queryByRoleName(String name) {
    	return sysRoleDao.queryByRoleName(name);
    }

	/**
	 * 查询组织下的角色
	 * @param params 组织ID
	 * @return 角色列表
	 */
	public List<SysRole> queryRolesByOrgId(Map<String, Object> params) {
		return sysRoleDao.queryRolesByOrgId(params);
	}
}
